#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>

#include <vector>
#include <cmath>

#include "glCamera.h"

#define RAD2DEG(x) (x * 180/M_PI)


typedef int BOOL;
#define TRUE 1
#define FALSE 0

// mouse control
static GLint prev_x = 0;
static GLint prev_y = 0;
static BOOL g_bButton1Down = FALSE;
static BOOL g_bButton2Down = FALSE;


// angle of rotation for the camera direction
float angle=0.0f, slant=0.0f;
// actual vector representing the camera's direction
float lx=0.0f,lz=-1.0f, ly=0.0f;
// XZ position of the camera
float x=0.0f,z=0.0f;

glCamera Camera;


void drawRectangle() {
	const GLfloat squareVertices[] = {
		-1.0, 1.0, 0.0,               // Top left
		-1.0, -1.0, 0.0,              // Bottom left
		1.0, -1.0, 0.0,               // Bottom right
		1.0, 1.0, 0.0                 // Top right
	};

	
	glColor3f(0.8f, 0.0f, 0.0f);

	// translate rectangle wrt. left-right movement of camera
	glTranslatef(sin(angle)*6.0f, 0.0f, -cos(angle)*6.0f);
	// rotate rectangle wrt. to left-right movement of camera
	glRotatef(0-RAD2DEG(angle), 0.0, 1.0, 0.0);


    glVertexPointer(3, GL_FLOAT, 0, squareVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}

void drawSphere() {

	glColor3f(1.0f, 1.0f, 1.0f);

	// rotate sphere draw the wireframe rotated
	glRotatef(90,1.0f ,0.0f, 0.0f);
	glPolygonMode(GL_BACK, GL_LINE); // draw wireframe only on inside of the sphere
	glutSolidSphere(10,70,70);
	glPolygonMode(GL_BACK, GL_FILL);

}

void changeSize(int w, int h) {

	// Prevent a divide by zero, when window is too short
	// (you cant make a window of zero width).
	if (h == 0)
		h = 1;
	float ratio =  w * 1.0 / h;

        // Use the Projection Matrix
	glMatrixMode(GL_PROJECTION);

        // Reset Matrix
	glLoadIdentity();

	// Set the viewport to be the entire window
	glViewport(0, 0, w, h);

	// Set the correct perspective.
	gluPerspective(45.0f, ratio, 0.1f, 100.0f);

	// Get Back to the Modelview
	glMatrixMode(GL_MODELVIEW);
}

void renderScene(void) {

	// Clear Color and Depth Buffers

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	// Reset transformations
	glLoadIdentity();
	Camera.SetPerspective();

	glPushMatrix();
		drawSphere();
	glPopMatrix();

	glPushMatrix();
		drawRectangle();
	glPopMatrix();

	glutSwapBuffers();
}

void processNormalKeys(unsigned char key, int x, int y) {
	float fraction = 0.4f;

	if (key == 27)
		exit(0);
	switch (key) {
		case 'w':
			x += lx * fraction;
			z += lz * fraction;
			break;
		case 's':
			x -= lx * fraction;
			z -= lz * fraction;
			break;
	}
}

void processSpecialKeys(int key, int xx, int yy) {

	float fraction = 0.4f;

	switch (key) {
		case GLUT_KEY_LEFT :
			Camera.ChangeYaw(1.0f);
/*			angle -= 0.1f;
			lx = sin(angle);
			lz = -cos(angle);
			break;
*/
		case GLUT_KEY_RIGHT :
			Camera.ChangeYaw(-1.0f);
/*
			angle += 0.1f;
			lx = sin(angle);
			lz = -cos(angle);
*/
			break;
/*
		case GLUT_KEY_UP :
			slant += 0.1f;
			ly = sin(slant);
			lz = -cos(slant);
			printf("ly: %f lz: %f\n", ly, lz);	
			if (lz > 0.9f) lz = 0.9f;
			break;
		case GLUT_KEY_DOWN :
			slant -= 0.1f;
			ly = sin(slant);
			lz = -cos(slant);
			printf("ly: %f lz: %f\n", ly, lz);	
			if (lz < 0.1f) lz = 0.1f;
			break;
*/
	}
}

/*  call when mouse button is pressed  */
void MouseClicks(int button, int state, int x, int y) {

	switch (button) {
	case GLUT_LEFT_BUTTON:
		g_bButton1Down = (state == GLUT_DOWN) ? TRUE : FALSE;
		break;
	case GLUT_RIGHT_BUTTON:
		g_bButton2Down = (state == GLUT_DOWN) ? TRUE : FALSE;
		break;
	}
}

void MouseMotion(int x, int y)
{
	if (g_bButton1Down)
	{
		printf("mouse x: %d mouse y: %d\n", x, y);

		int width = glutGet(GLUT_WINDOW_WIDTH);
		int height = glutGet(GLUT_WINDOW_HEIGHT);
		printf("screen width: %d height: %d\n", width, height);

		if (prev_x- x < 0) {
			glutPostRedisplay();
		}
		else if (prev_x - x > 0) {
            glutPostRedisplay();
		}

	
	}
	prev_x = x;
	prev_y = y;
}

int glInit() {
    // Now set up our max values for the camera
	glEnable(GL_DEPTH_TEST);

    Camera.m_MaxForwardVelocity = 5.0f;
    Camera.m_MaxPitchRate = 5.0f;
    Camera.m_MaxRollRate = 5.0f;
    Camera.m_MaxYawRate = 5.0f;
    Camera.m_RollDegrees = 0.0f;
    Camera.m_PitchDegrees = 0.0f;
    Camera.m_YawDegrees = 0.0f;
    // Initialization Went OK
    return TRUE;
}


int main(int argc, char **argv) {

	// init GLUT and create window

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(640,480);
	glutCreateWindow("Spherical User Interface");

	// register callbacks
	glutDisplayFunc(renderScene);
	glutReshapeFunc(changeSize);
	glutIdleFunc(renderScene);
	glutKeyboardFunc(processNormalKeys);
	glutSpecialFunc(processSpecialKeys);
    glutMouseFunc(MouseClicks);
	glutMotionFunc (MouseMotion);
	// OpenGL init
	glInit();

	// enter GLUT event processing cycle
	glutMainLoop();
}
